package com.demo.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * SpringApplication简单运行流程：
 * 1. 判断是否是Web环境
 * 2. 加载所有classpath下面的META-INF/spring.factories下的   ApplicationContextInitializer
 * 3. 加载所有classpath下面的META-INF/spring.factories下的   ApplicationListener
 * 4. 推断Main方法
 * 5. 开始执行run方法
 * 6. 设置java.awt.headless系统变量
 * 7. 加载所有classpath下面的META-INF/spring.factories      SpringApplicationRunListener
 * 8. 执行所有SpringApplicationRunListener的starting方法
 * 9. 实例化ApplicationArguments对象
 * 10.environment
    *      1.创建：
    *      2.配置，主要把run方法的参数传进去
    *      3.执行所有SpringApplicationRunListener的environmentPrepared方法
    *      4.如果不是web环境，而是web的environment，则把这个environment转换为标准的environment
 * 11. 输出Banner
 * 12. 初始化ApplicationContext，如果是Web环境则实例化AnnotationConfigServletWebServerApplicationContext对象
 *      否则实例化AnnotationConfigApplicationContext对象
 * 13. prepareContext：
     *     1.如果beanNameGenerator不为空，就把beanNameGenerator注入到Context 中去
     *     2.回调所有的ApplicationContextInitializer.initialize()方法
     *     3.执行所有的SpringApplicationRunListener 的 contextPrepared
     *     4.依次将applicationArguments，banner 注入spring容器
     *     5.加载所有的source到context
     *     6.执行所有的SpringApplicationRunListener 的 contextLoaded
 * 14. 执行context的refresh方法，并且调用context的registerShutdownHook方法(可以通过SpringApplication的setRegisterShutdownHook(false)关掉)
 * 15. 回调，获取所有的ApplicationRunner、CommandLineRunner接口，然后排序，依次调用
 * 16. 停止监控，执行所有的SpringApplicationRunListener的started方法
 */
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        ConfigurableApplicationContext context;

        // 方法①： 实例化SpringApplication方法，然后调用Run方法
        SpringApplication app = new SpringApplication(App.class);
        context = app.run(args);

        // 方法②： 直接调用静态的run方法(内部转换为第一种)
        // context = SpringApplication.run(App.class,args);

        context.close();
    }
}
